package com.linkhub.oms.data.sync.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.linkhub.oms.common.enums.mp.DataSyncTypeEnum;
import com.linkhub.oms.common.enums.mp.PlatFormEnum;
import com.linkhub.oms.common.util.CacheKeyAssist;
import com.linkhub.oms.common.util.OffSetDateTimeUtil;
import com.linkhub.oms.common.util.QtAopUtil;
import com.linkhub.oms.common.util.QtOptionalUtil;
import com.linkhub.oms.component.redis.locker.DistributedLocker;
import com.linkhub.oms.dao.mpservice.IChannelPriorityService;
import com.linkhub.oms.dao.mpservice.IShopService;
import com.linkhub.oms.data.sync.api.shopify.domain.dto.DataSyncRecordDTO;
import com.linkhub.oms.data.sync.api.shopify.domain.response.BaseResponse;
import com.linkhub.oms.data.sync.api.shopify.domain.response.ShopOrderResponse;
import com.linkhub.oms.data.sync.api.shopify.domain.response.ShopProductResponse;
import com.linkhub.oms.data.sync.api.shopify.domain.response.ShopShippingNameResponse;
import com.linkhub.oms.data.sync.service.DataSyncRecordBizService;
import com.linkhub.oms.data.sync.service.OrderSyncBizService;
import com.linkhub.oms.data.sync.service.ProductSyncBizService;
import com.linkhub.oms.data.sync.service.ShopifyApiService;
import com.linkhub.oms.data.sync.service.ShopifyDataSyncBizService;
import com.linkhub.oms.entity.ShopEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;

import static com.linkhub.oms.common.constant.ProjectConstant.ASYNC_EXECUTOR;
import static com.linkhub.oms.common.constant.ShopifyConstant.ORDER_DATA_TYPE_KEY;
import static com.linkhub.oms.common.constant.ShopifyConstant.PRODUCT_DATA_TYPE_KEY;

/**
 * @Description: ShopifyDataSyncBizService
 * @Author: echo
 * @Date: 2024/3/23 10:02
 * @Version: 1.0
 */
@Slf4j
@Service
public class ShopifyDataSyncBizServiceImpl implements ShopifyDataSyncBizService {

    @Resource
    private ShopifyApiService shopifyApiService;
    @Resource
    private DistributedLocker distributedLocker;
    @Resource
    private DataSyncRecordBizService dataSyncRecordBizService;
    @Resource
    private ProductSyncBizService productSyncBizService;
    @Resource
    private IShopService shopService;
    @Resource
    private OrderSyncBizService orderSyncBizService;
    @Resource
    private IChannelPriorityService channelPriorityService;

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public Integer syncShopProducts(ShopEntity shopEntity) {
        if (!PlatFormEnum.SHOPIFY.equals(shopEntity.getPlatForm())) {
            return 0;
        }
        ShopProductResponse shopProductResponse = this.syncShopifyData(shopEntity,
                PRODUCT_DATA_TYPE_KEY,
                DataSyncTypeEnum.SHOPIFY_PRODUCT,
                (updateTime) -> shopifyApiService.pullShopAllProducts(shopEntity.getUrl(),
                        shopEntity.getAccessToken(), updateTime),
                response -> productSyncBizService.sync(shopEntity.getSysShopId(), response)
        );

        return QtOptionalUtil.of(shopProductResponse)
                .map(ShopProductResponse::getSkuCount)
                .orElse(0);

    }

    @Override
    public void syncAllShopProducts() {
        List<ShopEntity> shops = shopService.listAllAuthorizationShops();
        if (CollUtil.isEmpty(shops)) {
            return;
        }
        for (ShopEntity shop : shops) {
            QtAopUtil.getProxyObject(this).asyncPullShopProducts(shop);

        }
    }

    @Override
    public void syncAllShopShippingName() {
        List<ShopEntity> shops = shopService.listAllAuthorizationShops();
        if (CollUtil.isEmpty(shops)) {
            return;
        }
        for (ShopEntity shop : shops) {
            QtAopUtil.getProxyObject(this).asyncPullShopShippingName(shop);

        }
    }

    @Override
    @Async(ASYNC_EXECUTOR)
    public void asyncPullShopProducts(ShopEntity shopEntity) {
        QtAopUtil.getProxyObject(this).syncShopProducts(shopEntity);
    }

    @Override
    @Async(ASYNC_EXECUTOR)
    public void batchAsyncPullShopProducts( List<ShopEntity> shops ) {
        for (ShopEntity shop : shops) {
            QtAopUtil.getProxyObject(this).asyncPullShopOrders(shop);
        }
    }

    @Override
    public void syncAllShopOrders() {
        List<ShopEntity> shops = shopService.listAllAuthorizationShops();
        if (CollUtil.isEmpty(shops)) {
            return;
        }
        for (ShopEntity shop : shops) {
            QtAopUtil.getProxyObject(this).asyncPullShopOrders(shop);

        }
    }

    @Override
    @Async(ASYNC_EXECUTOR)
    public void asyncPullShopOrders(ShopEntity shopEntity) {
        QtAopUtil.getProxyObject(this).syncShopOrders(shopEntity);
    }

    @Override
    @Async(ASYNC_EXECUTOR)
    public void asyncPullShopShippingName(ShopEntity shopEntity) {
        QtAopUtil.getProxyObject(this).syncShopShippingName(shopEntity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void syncShopShippingName(ShopEntity shopEntity) {
        String userId = shopEntity.getUserId();
        String sysShopId = shopEntity.getSysShopId();
        String url = shopEntity.getUrl();
        String accessToken = shopEntity.getAccessToken();
        ShopShippingNameResponse shopShippingName = shopifyApiService.getShopShippingName(url, accessToken);
        Set<String> shopShippingNames = extractUniqueShippingRates(shopShippingName);
        channelPriorityService.saveShippingName(userId,sysShopId,shopShippingNames);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public ShopOrderResponse syncShopOrders(ShopEntity shopEntity) {
        if (!PlatFormEnum.SHOPIFY.equals(shopEntity.getPlatForm())) {
            ShopOrderResponse shopOrderResponse = new ShopOrderResponse();
            List<ShopOrderResponse.Orders> ordersList = new ArrayList<>();
            shopOrderResponse.setOrders(ordersList);
            return shopOrderResponse;
        }
        
        ShopOrderResponse res = this.syncShopifyData(shopEntity,
                ORDER_DATA_TYPE_KEY,
                DataSyncTypeEnum.SHOPIFY_ORDER,
                (updateTime) -> shopifyApiService.pullShopAllOrders(shopEntity.getUrl(),
                        shopEntity.getAccessToken(), updateTime),

                orderRes -> orderSyncBizService.sync(shopEntity.getSysShopId(), orderRes)
        );

        return QtOptionalUtil.of(res)
                .orElse(ShopOrderResponse.emptyResponse());

    }

    private <R extends BaseResponse> R syncShopifyData(ShopEntity shop,
                                                       String lockKeySuffix,
                                                       DataSyncTypeEnum syncType,
                                                       Function<String, R> apiClient,
                                                       Consumer<R> dbSync) {


        String sysShopId = shop.getSysShopId();
        String lockKey = CacheKeyAssist.getShopifyDataSyncLockKey(sysShopId, lockKeySuffix);
        try {
            if (!distributedLocker.tryLock(lockKey)) {
                return null;
            }
            String latestSyncUpdateTime = dataSyncRecordBizService.getLatestSyncUpdateTime(sysShopId, syncType);
            R res = apiClient.apply(latestSyncUpdateTime);
            if (!res.success()) {
                return null;
            }

            // 落库: 新增、更新、删除
            dbSync.accept(res);

            // 记录maxUpdateTime
            int count = res.count();
            String updatedAt = res.maxUpdateTime();
            String maxUpdateTime = OffSetDateTimeUtil.plusShopifyUpdateAtOneSeconds(updatedAt);
            DataSyncRecordDTO recordDTO = new DataSyncRecordDTO(sysShopId, maxUpdateTime, syncType, count);
            dataSyncRecordBizService.saveRecord(recordDTO);

            return res;

        } finally {
            distributedLocker.unlock(lockKey);
        }
    }

    public static Set<String> extractUniqueShippingRates(ShopShippingNameResponse shopShippingNameResponse) {
        Set<String> uniqueRates = new HashSet<>();
        if (shopShippingNameResponse == null) {
            return uniqueRates;
        }
        List<ShopShippingNameResponse.ShippingZones> shippingZonesList = shopShippingNameResponse.getShippingZonesList();
        if (shippingZonesList!=null){
            for (ShopShippingNameResponse.ShippingZones shippingZones:shippingZonesList){
                List<ShopShippingNameResponse.PriceBasedShippingRate> priceBasedShippingRates = shippingZones.getPriceBasedShippingRates();
                if (priceBasedShippingRates != null) {
                    for (ShopShippingNameResponse.PriceBasedShippingRate priceBasedShippingRate : priceBasedShippingRates) {
                        String name = priceBasedShippingRate.getName();
                        if (!name.isEmpty()) {
                            uniqueRates.add(name);
                        }
                    }
                }

                List<ShopShippingNameResponse.WeightBasedShippingRate> weightBasedShippingRates = shippingZones.getWeightBasedShippingRates();
                if (weightBasedShippingRates != null) {
                    for (ShopShippingNameResponse.WeightBasedShippingRate weightBasedShippingRate : weightBasedShippingRates) {
                        String name = weightBasedShippingRate.getName();
                        if (!name.isEmpty()) {
                            uniqueRates.add(name);
                        }
                    }
                }
            }
        }
        return uniqueRates;
    }
}
